home *** CD-ROM | disk | FTP | other *** search
/ Speccy ClassiX 1998 / Speccy ClassiX 98.iso / amiga_system / the_aminet / dev / gcc / ixemulsrc.lha / ixemul-41.4 / library / __plock.c < prev    next >
C/C++ Source or Header  |  1995-09-27  |  17KB  |  595 lines

  1. /*
  2.  *  This file is part of ixemul.library for the Amiga.
  3.  *  Copyright (C) 1991, 1992  Markus M. Wild
  4.  *
  5.  *  This library is free software; you can redistribute it and/or
  6.  *  modify it under the terms of the GNU Library General Public
  7.  *  License as published by the Free Software Foundation; either
  8.  *  version 2 of the License, or (at your option) any later version.
  9.  *
  10.  *  This library is distributed in the hope that it will be useful,
  11.  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
  12.  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  13.  *  Library General Public License for more details.
  14.  *
  15.  *  You should have received a copy of the GNU Library General Public
  16.  *  License along with this library; if not, write to the Free
  17.  *  Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  18.  *
  19.  *  __plock.c,v 1.1.1.1 1994/04/04 04:30:12 amiga Exp
  20.  *
  21.  *  __plock.c,v
  22.  * Revision 1.1.1.1  1994/04/04  04:30:12  amiga
  23.  * Initial CVS check in.
  24.  *
  25.  *  Revision 1.2  1992/08/09  20:38:34  amiga
  26.  *  change to use 2.x header files by default
  27.  *
  28.  *  Revision 1.1  1992/05/14  19:55:40  mwild
  29.  *  Initial revision
  30.  *
  31.  */
  32.  
  33. /* 20-jan-92    -mw-    revamped to emulate GetDeviceProc() under 1.3
  34.  *            new way to find out whether IsFileSystem(name)
  35.  * 14-mar-92    -mw-    limited /sys -> sys: mapping. `/' is now treated
  36.  *            as undefined path, to be compatible to a later
  37.  *            version, where it will be a virtual directory
  38.  *            of devices and logicals
  39.  */
  40.  
  41. /*
  42.  * Lock() and LLock() emulation. Takes care of expanding paths that contain
  43.  * symlinks. 
  44.  * Call __plock() if you need a lock to the parent directory as used in
  45.  * other packets, that way you always get the "right" thing
  46.  */
  47.  
  48. #define KERNEL
  49. #include "ixemul.h"
  50. #include "kprintf.h"
  51.  
  52. #include <stdlib.h>
  53. #include <string.h>
  54.  
  55. /* don't need async packets in here, no shared file packets are in use */
  56. #define __srwport (u.u_sync_mp)
  57.  
  58. static struct DevProc    *get_device_proc (char *, struct DevProc *, int *);
  59. static void         free_device_proc (struct DevProc *);
  60. static int        unslashify (char *);
  61.  
  62. BPTR
  63. __plock (char *file_name, int (*last_func)(), void *last_arg)
  64. {
  65.   BPTR parent_lock;
  66.   struct MsgPort *handler;
  67.   struct StandardPacket *sp;
  68.   unsigned char *bstr;
  69.   char *sep, *next, *cp;
  70.   int len;
  71.   /* true when we're processing the last element of name */
  72.   int is_last;
  73.   /* true after first pass, we should unlock all locks except the one
  74.    * we get as a sideeffect of DeviceProc */
  75.   int unlock_parent;
  76.   int link_levels;
  77.   int no_error;
  78.   BPTR result;
  79.   int res_res2;
  80.   int omask;
  81.   int split_name;
  82.   struct DevProc *dp;
  83.   char *orig_name, *name;
  84.  
  85.   KPRINTF (("__plock: file_name = %s, last_func = $%lx\n", 
  86.         file_name ? file_name : "(none)", last_func));
  87.  
  88.   /* ``fix'' until I find the real problem in pdksh.. */
  89.   if (! file_name)
  90.     return 0;
  91.  
  92.   /* need to operate on a backup of the passed name, so I can do
  93.    * /sys -> sys: conversion in place */
  94.   name = alloca (strlen (file_name) + 1);
  95.   strcpy (name, file_name);
  96.   orig_name = name;
  97.  
  98.   /* now get a LONG aligned packet */
  99.   sp = alloca (sizeof(*sp)+2);
  100.   sp = LONG_ALIGN (sp);
  101.   __init_std_packet(sp);
  102.  
  103.   /* allocate one BSTR-buffer. A length of 255 is enough, since a bstr
  104.    * can't address any more ;-) */
  105.   bstr = alloca (256 + 2);
  106.   bstr = LONG_ALIGN (bstr);
  107.   
  108.   /* NOTE: although we don't use any DOS calls here, we have to block
  109.    * any signals, since the locks we obtain in this function have to
  110.    * be freed before anything else can be done. This function is
  111.    * *not* reentrant in the sense that it can be interrupted without
  112.    * being finished */
  113.   omask = syscall (SYS_sigsetmask, ~0);
  114.  
  115.   dp = 0;
  116.  
  117. retry_multi_assign:
  118.  
  119.   name = orig_name;
  120.   if (ix.ix_translate_slash && unslashify (name) < 0)
  121.     {
  122.       result = 0;
  123.       res_res2 = ERROR_OBJECT_NOT_FOUND;
  124.       dp = 0;
  125.       goto do_return;
  126.     }
  127.  
  128.   if (! strcmp (name, "*") || ! strcasecmp (name, "console:"))
  129.     {
  130.       handler = (struct MsgPort *)(((struct Process *)FindTask (0))->pr_ConsoleTask);
  131.       parent_lock = 0;
  132.       KPRINTF (("__plock: console override, handler $%lx.\n", handler));
  133.       name = "CONSOLE:";
  134.       if (dp) free_device_proc (dp);
  135.       split_name = 0;
  136.       dp = 0;
  137.     }
  138.   else if (! strcasecmp (name, "nil:") || ! strcasecmp (name, "/nil") ||
  139.       ! strcmp (name, "/dev/null") || ! strcmp (name, "dev:null"))
  140.     {
  141.     result = 0;
  142.         res_res2 = 4242;    /* special special ;-)))) */
  143.         dp = 0;
  144.         goto do_return;
  145.     }
  146.   else
  147.     {
  148.       dp = get_device_proc (name, dp, &split_name);
  149.       KPRINTF (("__plock: gdp(%s) -> $%lx",name,dp));
  150.  
  151.       handler = dp ? dp->dvp_Port : 0;
  152.       parent_lock = dp ? dp->dvp_Lock : 0;
  153.       if (handler)
  154.         KPRINTF (("  handler = $%lx, parent_lock = $%lx, is_fs = %ld\n", handler, parent_lock, split_name));
  155.       else
  156.         KPRINTF (("\n"));
  157.     }
  158.  
  159.   is_last = 0;
  160.   unlock_parent = 0;
  161.   link_levels = 0;
  162.   result = 0;
  163.  
  164.   if (! handler) 
  165.     {
  166.       res_res2 = ERROR_OBJECT_NOT_FOUND;
  167.       goto do_return;
  168.     }
  169.  
  170.   link_levels = 0;
  171.  
  172.   /* this seems logical, doesn't it? don't know ;-)) */
  173.   sep = index (name, ':');
  174.   if (sep) name = sep+1;
  175.  
  176.   do
  177.     {
  178.       KPRINTF (("__plock: solving for %s.\n", name));
  179.  
  180.       if (split_name)
  181.         {
  182.       /* fetch the first part of "name", thus stopping at either a : or a / 
  183.        * next points at the start of the next directory component to be
  184.        * processed in the next run
  185.        */
  186.  
  187.       sep = index (name, ':');
  188.       if (sep) 
  189.         {
  190.           sep++; /* the : is part of the filename */
  191.           next = sep;
  192.         }
  193.       else
  194.         {
  195.           sep = index (name, '/');
  196.           
  197.           /* map foo/bar/ into foo/bar, but keep foo/bar// */
  198.           if (sep && sep[1]==0)
  199.             {
  200.               is_last = 1;
  201.               next = sep;
  202.             }
  203.           else if (! sep)
  204.             {
  205.               sep = name + strlen (name);
  206.               next = sep;
  207.               is_last = 1;
  208.             }
  209.           else
  210.             {
  211.               if (ix.ix_translate_slash)
  212.             for (next = sep + 1; *next == '/'; next ++) ;
  213.           else
  214.             next = sep + 1;
  215.         
  216.               /* if the slash is the first character, it means "parent",
  217.                * so we have to pass it literally to Lock() */
  218.               if (sep == name) sep = next;
  219.             }
  220.         }
  221.     }
  222.       else
  223.     {
  224.       sep = name + strlen (name);
  225.       is_last = 1;
  226.     }
  227.  
  228.       len = sep - name;
  229.       if (len) bcopy (name, bstr + 1, len);
  230.       *bstr = len;
  231.  
  232.       if (ix.ix_translate_dots)
  233.     {
  234.           /* turn a ".." into a "/", and a "." into a "" */
  235.  
  236.       if (bcmp (bstr, "\2..", 3) == 0)
  237.         {
  238.           bstr[0] = 1; bstr[1] = '/';
  239.         }
  240.       else if (bcmp (bstr, "\1.", 2) == 0)
  241.         bstr[0] = 0;
  242.     }
  243.  
  244.       do
  245.     {
  246.           sp->sp_Pkt.dp_Port = __srwport;
  247.       if (! is_last)
  248.         {
  249.               sp->sp_Pkt.dp_Type = ACTION_LOCATE_OBJECT;
  250.               sp->sp_Pkt.dp_Arg1 = parent_lock;
  251.               sp->sp_Pkt.dp_Arg2 = CTOBPTR(bstr);
  252.               sp->sp_Pkt.dp_Arg3 = ACCESS_READ;
  253.  
  254.               PutPacket(handler, sp);
  255.               __wait_sync_packet(sp);
  256.  
  257.           no_error = sp->sp_Pkt.dp_Res1 > 0;
  258.         }
  259.       else
  260.         if (! (*last_func)(sp, handler, parent_lock, CTOBPTR (bstr),
  261.                                last_arg, &no_error)) break;
  262.  
  263.       /* if no error, fine */
  264.           if (no_error) break;
  265.  
  266.       /* else check whether ordinary error or really symlink */
  267.           if (sp->sp_Pkt.dp_Res2 != ERROR_IS_SOFT_LINK) break;
  268.  
  269.       /* read the link. temporarily use our bstr as a cstr, thus setting
  270.            * a terminating zero byte and skipping the length byte */
  271.       bstr[*bstr + 1] = 0;
  272.  
  273.           sp->sp_Pkt.dp_Port = __srwport;
  274.           sp->sp_Pkt.dp_Type = ACTION_READ_LINK;
  275.           sp->sp_Pkt.dp_Arg1 = parent_lock;
  276.           sp->sp_Pkt.dp_Arg2 = (long) (bstr + 1); /* read as cstr */
  277.           sp->sp_Pkt.dp_Arg3 = (long) (bstr + 1); /* write as cstr, same place */
  278.           sp->sp_Pkt.dp_Arg4 = 255; /* what a BSTR can address */
  279.  
  280.           PutPacket(handler, sp);
  281.           __wait_sync_packet(sp);
  282.  
  283.       /* error (no matter which...) couldn't read the link */
  284.       if (sp->sp_Pkt.dp_Res1 <= 0)
  285.         {
  286.           /* this is our error-"lock", so make sure it is really zero */
  287.           sp->sp_Pkt.dp_Res1 = 0;
  288.           break;
  289.             }
  290.  
  291.       /* oky, new name. Set up as bstr and retry to lock it */
  292.       *bstr = sp->sp_Pkt.dp_Res1;
  293.  
  294.       /* if the read name is absolute, we may have to change the
  295.        * handler and the parent lock. Check for this */
  296.       bstr[*bstr + 1] = 0;
  297.       
  298.       /* this isn't enabled by default, because it makes normal dos calls
  299.        * fail miserably */
  300.       if (ix.ix_translate_symlinks && unslashify (bstr + 1) < 0)
  301.         {
  302.           sp->sp_Pkt.dp_Res1 = 0;
  303.           sp->sp_Pkt.dp_Res2 = ERROR_OBJECT_NOT_FOUND;
  304.           break;
  305.         }
  306.       
  307.       if (cp = index ((char *)bstr + 1, ':'))
  308.         {
  309.               if (unlock_parent)
  310.             {
  311.                   sp->sp_Pkt.dp_Port = __srwport;
  312.                   sp->sp_Pkt.dp_Type = ACTION_FREE_LOCK;
  313.                   sp->sp_Pkt.dp_Arg1 = parent_lock;
  314.  
  315.                   PutPacket(handler, sp);
  316.                   __wait_sync_packet(sp);
  317.             }
  318.  
  319.           /* if this is ":foobar", then the handler stays the same, and the
  320.            * parent_lock gets zero. Don't need get_device_proc() to find
  321.            * this out ;-) */
  322.           if (cp == (char *)bstr+1)
  323.         parent_lock = 0;
  324.           else
  325.           /*
  326.            * NOTE: Multiassigns are currently only supported as the first
  327.            *       part of a path name. I don't like the idea of setting up
  328.            *       another recursion level here just to parse them...
  329.            *
  330.            * This approach also makes symbolic links to non-fs devices
  331.            * limited, which is bad. I'll HAVE to think something up
  332.            * (so you can't for example have dev:tty -> con:0/0/640/100/tty)
  333.            */
  334.               handler = DeviceProc (bstr + 1);    /* XXX fix !!! */
  335.               parent_lock = IoErr ();
  336.               unlock_parent = 0;
  337.               
  338.               if (! handler)
  339.                 {
  340.                   /* interesting bug.. long not noticed... */
  341.  
  342.           sp->sp_Pkt.dp_Res1 = 0;
  343.           if (! strcasecmp (bstr + 1, "nil:"))
  344.             sp->sp_Pkt.dp_Res2 = 4242;
  345.           else
  346.             sp->sp_Pkt.dp_Res2 = ERROR_OBJECT_NOT_FOUND;
  347.           break;
  348.         }
  349.         }
  350.  
  351.       ++link_levels;
  352.     }
  353.       while (link_levels < MAXSYMLINKS);
  354.  
  355.       if (link_levels == MAXSYMLINKS)
  356.     {
  357.       result = 0;
  358.       res_res2 = ERROR_TOO_MANY_LEVELS;
  359.     }
  360.       else
  361.     {
  362.       result = sp->sp_Pkt.dp_Res1;
  363.       res_res2 = sp->sp_Pkt.dp_Res2;
  364.     }
  365.  
  366.       if (unlock_parent)
  367.     {
  368.           sp->sp_Pkt.dp_Port = __srwport;
  369.           sp->sp_Pkt.dp_Type = ACTION_FREE_LOCK;
  370.           sp->sp_Pkt.dp_Arg1 = parent_lock;
  371.  
  372.           PutPacket(handler, sp);
  373.           __wait_sync_packet(sp);
  374.     }
  375.       else
  376.     unlock_parent = 1;
  377.  
  378.       parent_lock = result;
  379.       name = next;
  380.     }
  381.   while (no_error && ! is_last);
  382.  
  383.   /* yes I know it's ugly ... */
  384.   if (!no_error && res_res2 == ERROR_OBJECT_NOT_FOUND 
  385.       && dp && (dp->dvp_Flags & DVPF_ASSIGN))
  386.     goto retry_multi_assign;
  387.  
  388. do_return:
  389.   free_device_proc (dp);
  390.  
  391.   /* set up Result2 so that the IoErr() works */
  392.   ((struct Process *)FindTask (0))->pr_Result2 = res_res2;
  393.  
  394.   syscall (SYS_sigsetmask, omask);
  395.  
  396.   KPRINTF (("__plock: returning %ld, res2 = %ld.\n", result, res_res2));
  397.  
  398.   return result;
  399. }
  400.  
  401. /*
  402.  * this is somewhat similar to DeviceProc(), but with the difference that it's
  403.  * strictly passive, it won't start the handler, if it doesn't exist. This is
  404.  * vital to be able to deal with stubborn console handlers, that don't answer
  405.  * packets until they're really open..
  406.  * Returns:
  407.  *    HAN_UNDEF    device doesn't exist
  408.  *    HAN_CLONE_DEV    device exists, handler zero
  409.  *    HAN_FS_DEV    device exists, handler non-zero
  410.  *    HAN_NOT_A_DEV    exists, but is not a device
  411.  */
  412.  
  413. #define HAN_UNDEF    0
  414. #define HAN_CLONE_DEV    1
  415. #define HAN_FS_DEV    2
  416. #define    HAN_NOT_A_DEV    3
  417.  
  418. static int
  419. find_handler (char *bstr)
  420. {
  421.   struct DosLibrary *dl;
  422.   struct RootNode *rn;
  423.   struct DosInfo *di;
  424.   struct DevInfo *dv;
  425.   extern struct ixemul_base *ixemulbase;
  426.   int res = HAN_UNDEF;
  427.   
  428.   /* could probably use less drastic measures under 2.0... */
  429.   Forbid ();
  430.   dl = (struct DosLibrary *) ixemulbase->ix_dos_base;
  431.   rn = (struct RootNode *) dl->dl_Root;
  432.   di = BTOCPTR (rn->rn_Info);
  433.   for (dv = BTOCPTR (di->di_DevInfo); dv; dv = BTOCPTR (dv->dvi_Next))
  434.     {
  435. #if 0
  436. /* quite verbose output... */
  437.       {
  438.         char buf[255];
  439.         
  440.         bcopy (BTOCPTR (dv->dvi_Name)+1, buf, *(char *)BTOCPTR (dv->dvi_Name));
  441.         buf[*(char *)BTOCPTR (dv->dvi_Name)] = 0;
  442.         KPRINTF (("\t%s(%ld,$%lx)", buf, dv->dvi_Type, dv->dvi_Task));
  443.       }
  444. #endif
  445.  
  446.       if (! strncasecmp (bstr, BTOCPTR (dv->dvi_Name), bstr[0]+1))
  447.         {
  448.           if (dv->dvi_Type == DLT_DEVICE)
  449.             res = dv->dvi_Task ? HAN_FS_DEV : HAN_CLONE_DEV;
  450.           else
  451.         res = HAN_NOT_A_DEV;
  452.       break;
  453.     }
  454.     }
  455.   Permit ();
  456. /*  KPRINTF (("\n")); */
  457.   return res;
  458. }
  459.  
  460. /*
  461.  * feels very much like GetDeviceProc(), but works under 1.3 as well. Under
  462.  * 2.0, we're using the dos-library GetDeviceProc(), under 1.3 that is
  463.  * emulated with own structures.
  464.  * is_fs is filled out with a best guess approach, since we can't use the
  465.  * proper packet on a handler that isn't yet fully operating (as after just
  466.  * calling DevProc)
  467.  * if calling with prev!=0, is_fs is not touched.
  468.  */
  469.  
  470. static struct DevProc *
  471. get_device_proc (char *name, struct DevProc *prev, int *is_fs)
  472. {
  473.   char *cp, *f;
  474.   int len;
  475.   struct DevProc *dp;
  476.   int han = HAN_UNDEF;
  477.   struct Process *this_proc;
  478.   APTR oldwin;
  479.  
  480.   if (! prev)
  481.     {
  482.       /* have to prove the opposite */
  483.       *is_fs = 1;
  484.  
  485.       cp = index (name, ':');
  486.       if (cp && cp != name)    /* ":..." has to be a filesystem */
  487.         {
  488.           len = cp - name;
  489.           f = alloca (len + 1);
  490.           f[0] = len;
  491.           bcopy (name, f + 1, len);
  492.  
  493.           /* try to find it */
  494.           han = find_handler (f);
  495.  
  496.       KPRINTF (("  find_handler(%s) = %ld\n", name, han));
  497.  
  498.       /* this might be wrong, we'll know more after GetDeviceProc() */
  499.           if (han == HAN_CLONE_DEV) 
  500.             *is_fs = 0;
  501.         }
  502.     }
  503.  
  504.   if (ix.ix_no_insert_disk_requester)
  505.     {
  506.       this_proc = (struct Process *)FindTask (0);
  507.       oldwin = this_proc->pr_WindowPtr;
  508.       this_proc->pr_WindowPtr = (APTR)-1;
  509.     }
  510.   dp = GetDeviceProc (name, prev);  
  511.   if (ix.ix_no_insert_disk_requester)
  512.     this_proc->pr_WindowPtr = oldwin;
  513.  
  514.   /* Second approach to verify, if a handler probably is a file system or not.
  515.    * If the device is a filesystem, but didn't contain a volume before, then
  516.    * the GetDeviceProc() call will have popped up the `please insert a disk'
  517.    * requester. If the user obeyed, the handler will now exist. On the other
  518.    * hand, if the device really is a clone device, it will still be one (ie. have
  519.    * its task field zero), so check the device list again. */
  520.  
  521.   /* only for possible clone devices */
  522.   if (han == HAN_CLONE_DEV)
  523.     *is_fs = find_handler (f) != HAN_CLONE_DEV;
  524.   
  525.   return dp;
  526. }
  527.  
  528. static void
  529. free_device_proc (struct DevProc *dp)
  530. {
  531.   FreeDeviceProc (dp);
  532. }
  533.  
  534.  
  535. static int
  536. unslashify (char *name)
  537. {
  538.   char *oname = name;
  539.  
  540.   /* if we're here, make sure to return every attempt to use a colon inside
  541.    * a filename as an error. I could at least imagine, that it would be
  542.    * possible for the user to actually generate a file with colons in its
  543.    * name, but he would probably not be able to get rid of it again... */
  544.   if (index (name, ':'))
  545.     return ix.ix_force_translation ? -1 : 0;
  546.  
  547.   while (oname[0] == '/' && oname[1] == '/')
  548.     oname++;
  549.  
  550.   /* don't (!) use strcpy () here, this is an overlapping copy ! */
  551.   if (oname > name)
  552.     bcopy (oname, name, strlen (oname) + 1);
  553.     
  554.   /* This is marked as error, so that the user gets used to use `..' instead of
  555.    * `/' to really mean `parent directory', *iff* he/she enabled ix slash 
  556.    * translation (this function is only called if slash translation is enabled) */
  557.   if (name[0] == '/' && name[1] == 0)
  558.     return ix.ix_force_translation ? -1 : 0;
  559.  
  560.   if (name[0] == '/')
  561.     {
  562.       /* get the delimiter */
  563.       char *cp = index (name + 1, '/');
  564.       int shift = 0;
  565.  
  566.       /* if there is a separating (and not terminating) slash, shift a bit ;-) */
  567.       if (cp)
  568.     while (*cp == '/')
  569.           {
  570.             shift ++;
  571.         cp ++;
  572.       }
  573.  
  574.       /* is it a terminator (then discard it) or a separator ? */
  575.       if (! cp || !*cp)
  576.         {
  577.       /* terminator */
  578.           cp = name + strlen (name);
  579.           bcopy (name + 1, name, cp - name);
  580.           cp[-1-shift] = ':';
  581.           cp[-shift] = 0;
  582.     }
  583.       else
  584.     {
  585.       /* separator */
  586.       bcopy (name + 1, name, strlen (name) + 1);
  587.       cp --;
  588.       bcopy (cp, cp - (shift - 1), strlen (cp) + 1);
  589.       cp[-shift] = ':';
  590.     }
  591.     }
  592.  
  593.   return 0;
  594. }
  595.